/*************************************************************************
 *
 * Copyright 2019 Realm Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **************************************************************************/
#include <realm/decimal128.hpp>

#include <realm/string_data.hpp>
#include <realm/util/to_string.hpp>

#include <external/IntelRDFPMathLib20U2/LIBRARY/src/bid_conf.h>
#include <external/IntelRDFPMathLib20U2/LIBRARY/src/bid_functions.h>
#include <cstring>
#include <stdexcept>

namespace realm {

namespace {

Decimal128 to_decimal128(const BID_UINT128& val)
{
    Decimal128 tmp;
    memcpy(tmp.raw(), &val, sizeof(BID_UINT128));
    return tmp;
}

BID_UINT128 to_BID_UINT128(const Decimal128& val)
{
    BID_UINT128 ret;
    memcpy(&ret, val.raw(), sizeof(BID_UINT128));
    return ret;
}

} // namespace

Decimal128::Decimal128() noexcept
    : Decimal128(0)
{
}

/**
 * The following function is effectively 'binary64_to_bid128' from the Intel library.
 * All macros are expanded, so it is perhaps not that readable. The reason for
 * including it here is to avoid including 'bid_binarydecimal.c' in its entirety
 * as this would add around 2Mb of data to the binary.
 */

namespace {

typedef struct BID_ALIGN(16) {
    BID_UINT64 w[6];
} BID_UINT384;
typedef struct BID_ALIGN(16) {
    BID_UINT64 w[8];
} BID_UINT512;

static const BID_UINT128 bid_coefflimits_bid128[] = {{{4003012203950112768ull, 542101086242752ull}},
                                                     {{8179300070273843200ull, 108420217248550ull}},
                                                     {{1635860014054768640ull, 21684043449710ull}},
                                                     {{327172002810953728ull, 4336808689942ull}},
                                                     {{7444132030046011392ull, 867361737988ull}},
                                                     {{12556872850234933248ull, 173472347597ull}},
                                                     {{9890072199530807296ull, 34694469519ull}},
                                                     {{16735409698873802752ull, 6938893903ull}},
                                                     {{14415128384000491520ull, 1387778780ull}},
                                                     {{2883025676800098304ull, 277555756ull}},
                                                     {{4265953950101929984ull, 55511151ull}},
                                                     {{4542539604762296320ull, 11102230ull}},
                                                     {{908507920952459264ull, 2220446ull}},
                                                     {{3871050398932402176ull, 444089ull}},
                                                     {{15531605338754121728ull, 88817ull}},
                                                     {{10485018697234644992ull, 17763ull}},
                                                     {{13165050183672659968ull, 3552ull}},
                                                     {{10011707666218352640ull, 710ull}},
                                                     {{2002341533243670528ull, 142ull}},
                                                     {{7779165936132554752ull, 28ull}},
                                                     {{12623879631452241920ull, 5ull}},
                                                     {{2524775926290448384ull, 1ull}},
                                                     {{4194304000000000000ull, 0ull}},
                                                     {{838860800000000000ull, 0ull}},
                                                     {{167772160000000000ull, 0ull}},
                                                     {{33554432000000000ull, 0ull}},
                                                     {{6710886400000000ull, 0ull}},
                                                     {{1342177280000000ull, 0ull}},
                                                     {{268435456000000ull, 0ull}},
                                                     {{53687091200000ull, 0ull}},
                                                     {{10737418240000ull, 0ull}},
                                                     {{2147483648000ull, 0ull}},
                                                     {{429496729600ull, 0ull}},
                                                     {{85899345920ull, 0ull}},
                                                     {{17179869184ull, 0ull}},
                                                     {{3435973836ull, 0ull}},
                                                     {{687194767ull, 0ull}},
                                                     {{137438953ull, 0ull}},
                                                     {{27487790ull, 0ull}},
                                                     {{5497558ull, 0ull}},
                                                     {{1099511ull, 0ull}},
                                                     {{219902ull, 0ull}},
                                                     {{43980ull, 0ull}},
                                                     {{8796ull, 0ull}},
                                                     {{1759ull, 0ull}},
                                                     {{351ull, 0ull}},
                                                     {{70ull, 0ull}},
                                                     {{14ull, 0ull}},
                                                     {{2ull, 0ull}}};

static const BID_UINT128 bid_roundbound_128[] = {
    {{0ull, (1ull << 63)}},      // BID_ROUNDING_TO_NEAREST | positive | even
    {{~0ull, (1ull << 63) - 1}}, // BID_ROUNDING_TO_NEAREST | positive | odd
    {{0ull, (1ull << 63)}},      // BID_ROUNDING_TO_NEAREST | negative | even
    {{~0ull, (1ull << 63) - 1}}, // BID_ROUNDING_TO_NEAREST | negative | odd

    {{~0ull, ~0ull}}, // BID_ROUNDING_DOWN       | positive | even
    {{~0ull, ~0ull}}, // BID_ROUNDING_DOWN       | positive | odd
    {{0ull, 0ull}},   // BID_ROUNDING_DOWN       | negative | even
    {{0ull, 0ull}},   // BID_ROUNDING_DOWN       | negative | odd

    {{0ull, 0ull}},   // BID_ROUNDING_UP         | positive | even
    {{0ull, 0ull}},   // BID_ROUNDING_UP         | positive | odd
    {{~0ull, ~0ull}}, // BID_ROUNDING_UP         | negative | even
    {{~0ull, ~0ull}}, // BID_ROUNDING_UP         | negative | odd

    {{~0ull, ~0ull}}, // BID_ROUNDING_TO_ZERO    | positive | even
    {{~0ull, ~0ull}}, // BID_ROUNDING_TO_ZERO    | positive | odd
    {{~0ull, ~0ull}}, // BID_ROUNDING_TO_ZERO    | negative | even
    {{~0ull, ~0ull}}, // BID_ROUNDING_TO_ZERO    | negative | odd

    {{~0ull, (1ull << 63) - 1}}, // BID_ROUNDING_TIES_AWAY  | positive | even
    {{~0ull, (1ull << 63) - 1}}, // BID_ROUNDING_TIES_AWAY  | positive | odd
    {{~0ull, (1ull << 63) - 1}}, // BID_ROUNDING_TIES_AWAY  | negative | even
    {{~0ull, (1ull << 63) - 1}}  // BID_ROUNDING_TIES_AWAY  | negative | odd
};

// Table of powers of 5


static const BID_UINT128 bid_power_five[] = {{{1ull, 0ull}},
                                             {{5ull, 0ull}},
                                             {{25ull, 0ull}},
                                             {{125ull, 0ull}},
                                             {{625ull, 0ull}},
                                             {{3125ull, 0ull}},
                                             {{15625ull, 0ull}},
                                             {{78125ull, 0ull}},
                                             {{390625ull, 0ull}},
                                             {{1953125ull, 0ull}},
                                             {{9765625ull, 0ull}},
                                             {{48828125ull, 0ull}},
                                             {{244140625ull, 0ull}},
                                             {{1220703125ull, 0ull}},
                                             {{6103515625ull, 0ull}},
                                             {{30517578125ull, 0ull}},
                                             {{152587890625ull, 0ull}},
                                             {{762939453125ull, 0ull}},
                                             {{3814697265625ull, 0ull}},
                                             {{19073486328125ull, 0ull}},
                                             {{95367431640625ull, 0ull}},
                                             {{476837158203125ull, 0ull}},
                                             {{2384185791015625ull, 0ull}},
                                             {{11920928955078125ull, 0ull}},
                                             {{59604644775390625ull, 0ull}},
                                             {{298023223876953125ull, 0ull}},
                                             {{1490116119384765625ull, 0ull}},
                                             {{7450580596923828125ull, 0ull}},
                                             {{359414837200037393ull, 2ull}},
                                             {{1797074186000186965ull, 10ull}},
                                             {{8985370930000934825ull, 50ull}},
                                             {{8033366502585570893ull, 252ull}},
                                             {{3273344365508751233ull, 1262ull}},
                                             {{16366721827543756165ull, 6310ull}},
                                             {{8046632842880574361ull, 31554ull}},
                                             {{3339676066983768573ull, 157772ull}},
                                             {{16698380334918842865ull, 788860ull}},
                                             {{9704925379756007861ull, 3944304ull}},
                                             {{11631138751360936073ull, 19721522ull}},
                                             {{2815461535676025517ull, 98607613ull}},
                                             {{14077307678380127585ull, 493038065ull}},
                                             {{15046306170771983077ull, 2465190328ull}},
                                             {{1444554559021708921ull, 12325951644ull}},
                                             {{7222772795108544605ull, 61629758220ull}},
                                             {{17667119901833171409ull, 308148791101ull}},
                                             {{14548623214327650581ull, 1540743955509ull}},
                                             {{17402883850509598057ull, 7703719777548ull}},
                                             {{13227442957709783821ull, 38518598887744ull}},
                                             {{10796982567420264257ull, 192592994438723ull}}};

// These are the different, bipartite, tables for conversion to bid128
// Using the same approach, the tables become extremely large
// And things are more amenable here since there's never overflow/underflow

static const BID_UINT256 bid_outertable_sig[] = {
    {{16710528681477587410ull, 1427578414467097172ull, 17470362193306814444ull, 17633471421292828081ull}},
    {{15880413049339289368ull, 3169162604521042544ull, 12421848348224877000ull, 10175591536883283100ull}},
    {{728324709502741634ull, 5487234822932806241ull, 14277366029702694882ull, 11743877385420605756ull}},
    {{5270439690693945016ull, 5335305964155802506ull, 4731239033579481048ull, 13553871098685738146ull}},
    {{15770926697301461842ull, 17478494563481727979ull, 12172666691698088779ull, 15642825255298684824ull}},
    {{6706015564063194464ull, 9524484409513358023ull, 3584925281718916951ull, 18053733887991431306ull}},
    {{11970480524618434228ull, 11405570099769256704ull, 15462553542164535233ull, 10418108684938663938ull}},
    {{6786207772287397676ull, 2319456072422691258ull, 3306628541457879036ull, 12023771840725819358ull}},
    {{11981052113010165492ull, 3504057943690712651ull, 1876153621163772099ull, 13876903538819465956ull}},
    {{9393164661428669080ull, 12786250932199773041ull, 1469280998340568779ull, 16015644206874417279ull}},
    {{16924685242153318850ull, 18017830257179898541ull, 8443357802200517361ull, 9242006282008467740ull}},
    {{10964968671057563176ull, 5039440430669711539ull, 5426243050445487622ull, 10666405798403203685ull}},
    {{10955754838860298353ull, 7697974614691938479ull, 5802604364043796934ull, 12310337083160321132ull}},
    {{2020816881108765590ull, 11827301330378587775ull, 11428107909474365520ull, 14207634883319258514ull}},
    {{17088069107880998350ull, 4283872614129133981ull, 3596834484036483711ull, 16397348635874181367ull}},
    {{17878879927905357932ull, 16765016545576715295ull, 16689816215723394984ull, 9462273083962776199ull}},
    {{13121733289080687293ull, 18283685101712419716ull, 16276586284347626380ull, 10920620632484725600ull}},
    {{17814811358648632259ull, 13245640156276305425ull, 16363965810173909683ull, 12603732099085151178ull}},
    {{4756697993914874888ull, 11508234184157253656ull, 5137266535116401279ull, 14546248621894116172ull}},
    {{5318236458935323174ull, 6543830884414701181ull, 6453355338781772809ull, 16788150311867950084ull}},
    {{6485710970464102310ull, 9658720758000782538ull, 1405691438411884535ull, 9687789553853107178ull}},
    {{16668567668910748869ull, 7353216905500064137ull, 16398637311140236340ull, 11180894225541718927ull}},
    {{10250898639443956700ull, 17209112682100433509ull, 10404161081088486903ull, 12904119664018836844ull}},
    {{8190593687966138954ull, 9395575747272723417ull, 5270639644724875979ull, 14892932617404296676ull}},
    {{16096765186944088526ull, 5812137315202163815ull, 13827109944906121794ull, 17188266051577202911ull}},
    {{13125058493821651226ull, 13878096157524874998ull, 7819283672493662452ull, 9918680808189048078ull}},
    {{10784977039313888136ull, 7095114120404217728ull, 5980679097159643429ull, 11447370977331402726ull}},
    {{18074025829186132275ull, 1141984379626550674ull, 7557580538320593620ull, 13211666432945230258ull}},
    {{884127375074722974ull, 5630658839879210216ull, 8888788495242174599ull, 15247879210087606793ull}},
    {{14794677677148287412ull, 15991859528909753139ull, 2255166953101703543ull, 17597917839164816062ull}},
    {{11781503818372409883ull, 16487377189598053250ull, 1614766483381505408ull, 10155074945409931597ull}},
    {{13901203812957478350ull, 17671725616207330354ull, 9774501520532043416ull, 11720198729122693309ull}},
    {{2841277750318224700ull, 62614824260888948ull, 7875289095414864909ull, 13526543032773672749ull}},
    {{4177215723684349918ull, 5549883551398310595ull, 6548711429670794128ull, 15611285324269742443ull}},
    {{10113135653152274419ull, 1238174514434849746ull, 15010187426055142985ull, 18017332949391848572ull}},
    {{15332868447221136909ull, 16659234357027498643ull, 8156814090647504084ull, 10397103116953834012ull}},
    {{15245187402216469644ull, 12129929088655149192ull, 9861651730211963150ull, 11999528845718521943ull}},
    {{11169863271521019024ull, 11690833164181629132ull, 18055231442152805128ull, 13848924157002783033ull}},
    {{5681139181384005971ull, 16315598095635316730ull, 12429006944274865118ull, 15983352577617880224ull}},
    {{0ull, 0ull, 0ull, 9223372036854775808ull}},
    {{847738094735128551ull, 159020156881263929ull, 14298703881791668535ull, 10644899600020376799ull}},
    {{12571812103339493257ull, 9592188640606484874ull, 15977522551232326327ull, 12285516299433008781ull}},
    {{11255846670375652269ull, 16219642565822741785ull, 1164180458167399492ull, 14178988662640388631ull}},
    {{4768530159026621925ull, 11269558331910606010ull, 14728279675391465720ull, 16364287392998134214ull}},
    {{10435171899994305314ull, 3358688235984080491ull, 10873005112892106269ull, 9443194724678278428ull}},
    {{9001934648837042518ull, 12742858465034581069ull, 7821978264675184102ull, 10898601872067700364ull}},
    {{17621267265258286727ull, 4697230115438671198ull, 9730745556445007669ull, 12578319756070083561ull}},
    {{15489206033570711069ull, 5939008219696634639ull, 7281543418588385486ull, 14516919669433371671ull}},
    {{5582382164278045428ull, 1021128504191590019ull, 15859662269683349667ull, 16754301112998936544ull}},
    {{13306060077138970688ull, 17077419079040409017ull, 602300193611639289ull, 9668256495766433483ull}},
    {{16144900726383728979ull, 6332437060439625781ull, 3394061071468721991ull, 11158350687084940805ull}},
    {{841527738022137013ull, 8576187517129556015ull, 4780478900157118356ull, 12878101662951253988ull}},
    {{6209518431268106959ull, 6563228687006195825ull, 8680557599339190037ull, 14862904661462481806ull}},
    {{13777918056850427098ull, 13980713634323581067ull, 3260730320187665275ull, 17153610117183879308ull}},
    {{14026398967643035423ull, 16044002814696042637ull, 13563648246219923183ull, 9898682214361989196ull}},
    {{8580849201736980837ull, 7652064075251385167ull, 12055336643618066002ull, 11424290153682525668ull}},
    {{7703450277136593061ull, 30939122015382097ull, 1733744904199768989ull, 13185028339041359606ull}},
    {{16645858086931268484ull, 268706294728574543ull, 4562366333509913804ull, 15217135591158481007ull}},
    {{1535817262145462730ull, 16249574698204674087ull, 1726174694286833848ull, 17562435942139069664ull}},
    {{1327779613951528273ull, 12607890553358950732ull, 6773080245737622022ull, 10134599720625107110ull}},
    {{10146669700226523625ull, 6816618733538609533ull, 17338427607494047961ull, 11696567815043613180ull}},
    {{1218646606393179524ull, 8053984438814192242ull, 5512554737593155320ull, 13499270067222312908ull}},
    {{8529816360522570005ull, 2898610325645650649ull, 12799329154556421864ull, 15579808985797328396ull}},
    {{8976626101186384018ull, 17306366585957786234ull, 18289272351796647404ull, 17981005404381600394ull}},
    {{13259258789938866699ull, 3853966764738768487ull, 3962898110873089456ull, 10376139901559067117ull}},
    {{899097863387258947ull, 18205835716688941338ull, 5828614502416977816ull, 11975334730781032005ull}},
    {{6805696657844643720ull, 11269663690239600300ull, 15713752492130876427ull, 13821001188766021149ull}},
    {{1390669429605106863ull, 9874674503958832077ull, 10784451562526769943ull, 15951126056533488631ull}},
    {{5704986635434998471ull, 13359511205918707297ull, 13484363347568202582ull, 18409550726197325520ull}},
    {{8031416311578790746ull, 15203770801091158414ull, 10108131133879485063ull, 10623436763626360685ull}},
    {{14540970352057967818ull, 10823414366732926995ull, 16152175176069010361ull, 12260745560745135745ull}},
    {{15950896424073439808ull, 7311065895593189991ull, 14504991862333000338ull, 14150400200058902426ull}},
    {{5978819348613013533ull, 5596367464999577452ull, 9804643584580705193ull, 16331292810031855499ull}},
    {{8586457898440847299ull, 6018330550275346810ull, 7956755163056284140ull, 9424154832238877876ull}},
    {{1114429888821394320ull, 1760611426277998851ull, 9839409379426382903ull, 10876627507095459665ull}},
    {{7554605751361075608ull, 6504275622057553570ull, 9148491728899045148ull, 12552958650829068784ull}},
    {{9208049516541304162ull, 15518058123431536615ull, 17563500997894963674ull, 14487649851631658771ull}},
    {{1484107481346855224ull, 16657394431011607502ull, 12009304572091620947ull, 16720520162760224108ull}},
    {{14325586681310127114ull, 11250726580617083666ull, 2403442209646777766ull, 9648762821313776241ull}},
    {{14963893077912294692ull, 3450059817568720983ull, 15313875826588494017ull, 11135852602159508258ull}}};

static const BID_UINT256 bid_innertable_sig[] = {
    {{1014026100135492416ull, 3035406636157676337ull, 4549648098962661924ull, 12141680576410806693ull}},
    {{5879218643596753424ull, 3794258295197095421ull, 10298746142130715309ull, 15177100720513508366ull}},
    {{5980354661461664842ull, 4677254443711878590ull, 1825030320404309164ull, 9485687950320942729ull}},
    {{16698815363681856860ull, 5846568054639848237ull, 6892973918932774359ull, 11857109937901178411ull}},
    {{7038461149320157363ull, 2696524049872422393ull, 4004531380238580045ull, 14821387422376473014ull}},
    {{15928253264393568112ull, 3991170540383957947ull, 16337890167931276240ull, 9263367138985295633ull}},
    {{15298630562064572236ull, 4988963175479947434ull, 6587304654631931588ull, 11579208923731619542ull}},
    {{9899916165725939487ull, 6236203969349934293ull, 17457502855144690293ull, 14474011154664524427ull}},
    {{16986581225584812263ull, 12406940980114805770ull, 17210192550503474962ull, 18092513943330655534ull}},
    {{15228299284417895569ull, 12366024130999141510ull, 6144684325637283947ull, 11307821214581659709ull}},
    {{9812002068667593653ull, 10845844145321538984ull, 12292541425473992838ull, 14134776518227074636ull}},
    {{12265002585834492066ull, 4333933144797147922ull, 15365676781842491048ull, 17668470647783843295ull}},
    {{12277312634573945445ull, 2708708215498217451ull, 16521077016292638761ull, 11042794154864902059ull}},
    {{10734954774790043902ull, 7997571287800159718ull, 16039660251938410547ull, 13803492693581127574ull}},
    {{4195321431632779070ull, 5385278091322811744ull, 10826203278068237376ull, 17254365866976409468ull}},
    {{2622075894770486919ull, 3365798807076757340ull, 15989749085647424168ull, 10783978666860255917ull}},
    {{3277594868463108648ull, 4207248508845946675ull, 6152128301777116498ull, 13479973333575319897ull}},
    {{17932051640861049522ull, 14482432672912209151ull, 12301846395648783526ull, 16849966666969149871ull}},
    {{18125061303179237808ull, 4439834402142742815ull, 14606183024921571560ull, 10531229166855718669ull}},
    {{18044640610546659355ull, 5549793002678428519ull, 4422670725869800738ull, 13164036458569648337ull}},
    {{17944114744755936290ull, 16160613290202811457ull, 10140024425764638826ull, 16455045573212060421ull}},
    {{4297542687831378326ull, 14712069324804145065ull, 8643358275316593218ull, 10284403483257537763ull}},
    {{9983614378216610811ull, 9166714619150405523ull, 6192511825718353619ull, 12855504354071922204ull}},
    {{7867831954343375609ull, 6846707255510619000ull, 7740639782147942024ull, 16069380442589902755ull}},
    {{4917394971464609756ull, 4279192034694136875ull, 2532056854628769813ull, 10043362776618689222ull}},
    {{1535057695903374291ull, 9960676061795058998ull, 12388443105140738074ull, 12554203470773361527ull}},
    {{11142194156733993672ull, 3227473040389047939ull, 10873867862998534689ull, 15692754338466701909ull}},
    {{4658028338745052093ull, 13546385696311624722ull, 9102010423587778132ull, 9807971461541688693ull}},
    {{15045907460286090924ull, 16932982120389530902ull, 15989199047912110569ull, 12259964326927110866ull}},
    {{9584012288502837847ull, 7331169595204749916ull, 10763126773035362404ull, 15324955408658888583ull}},
    {{15213379717169049462ull, 13805353033857744505ull, 13644483260788183358ull, 9578097130411805364ull}},
    {{5181666591179148116ull, 8033319255467404824ull, 17055604075985229198ull, 11972621413014756705ull}},
    {{6477083238973935145ull, 818277032479480222ull, 7484447039699372786ull, 14965776766268445882ull}},
    {{17883235079640873178ull, 5123109163727063042ull, 9289465418239495895ull, 9353610478917778676ull}},
    {{13130671812696315664ull, 1792200436231440899ull, 11611831772799369869ull, 11692013098647223345ull}},
    {{11801653747443006676ull, 6851936563716689028ull, 679731660717048624ull, 14615016373309029182ull}},
    {{14752067184303758345ull, 8564920704645861285ull, 10073036612751086588ull, 18268770466636286477ull}},
    {{11525884999403542918ull, 14576447477258439111ull, 8601490892183123069ull, 11417981541647679048ull}},
    {{9795670230827040743ull, 4385501291290885177ull, 10751863615228903837ull, 14272476927059598810ull}},
    {{16856273806961188833ull, 10093562632540994375ull, 4216457482181353988ull, 17840596158824498513ull}},
    {{17452700156991824877ull, 15531848682192897292ull, 14164500972431816002ull, 11150372599265311570ull}},
    {{3369131122530229480ull, 10191438815886345808ull, 8482254178684994195ull, 13937965749081639463ull}},
    {{4211413903162786849ull, 8127612501430544356ull, 5991131704928854840ull, 17422457186352049329ull}},
    {{11855505726331517589ull, 5079757813394090222ull, 15273672361649004035ull, 10889035741470030830ull}},
    {{5596010121059621178ull, 1738011248315224874ull, 9868718415206479236ull, 13611294676837538538ull}},
    {{16218384688179302281ull, 2172514060394031092ull, 3112525982153323237ull, 17014118346046923173ull}},
    {{913118393257288118ull, 3663664296959963385ull, 4251171748059520975ull, 10633823966279326983ull}},
    {{5753084009998998051ull, 18414638426482117943ull, 702278666647013314ull, 13292279957849158729ull}},
    {{2579668994071359659ull, 13794925996247871621ull, 5489534351736154547ull, 16615349947311448411ull}},
    {{3918136130508293739ull, 6315985738441225811ull, 1125115960621402640ull, 10384593717069655257ull}},
    {{285984144707979270ull, 7894982173051532264ull, 6018080969204141204ull, 12980742146337069071ull}},
    {{357480180884974087ull, 9868727716314415330ull, 2910915193077788601ull, 16225927682921336339ull}},
    {{4835111131480496709ull, 17697169868764979341ull, 17960223060169475539ull, 10141204801825835211ull}},
    {{10655574932778008790ull, 17509776317528836272ull, 17838592806784456520ull, 12676506002282294014ull}},
    {{13319468665972510987ull, 3440476323201493724ull, 13074868971625794843ull, 15845632502852867518ull}},
    {{17548039953087595175ull, 18291198766496791241ull, 3560107088838733872ull, 9903520314283042199ull}},
    {{8099991886077330257ull, 4417254384411437436ull, 18285191916330581053ull, 12379400392853802748ull}},
    {{10124989857596662821ull, 10133253998941684699ull, 4409745821703674700ull, 15474250491067253436ull}},
    {{4022275651784220311ull, 15556655786193328745ull, 11979463175419572495ull, 9671406556917033397ull}},
    {{9639530583157663293ull, 14834133714314273027ull, 1139270913992301907ull, 12089258196146291747ull}},
    {{7437727210519691212ull, 13930981124465453380ull, 15259146697772541096ull, 15111572745182864683ull}},
    {{13871951543429582816ull, 8706863202790908362ull, 7231123676894144233ull, 9444732965739290427ull}},
    {{8116567392432202712ull, 15495265021916023357ull, 4427218577690292387ull, 11805916207174113034ull}},
    {{14757395258967641293ull, 14757395258967641292ull, 14757395258967641292ull, 14757395258967641292ull}},
    {{0ull, 0ull, 0ull, 9223372036854775808ull}},
    {{0ull, 0ull, 0ull, 11529215046068469760ull}},
    {{0ull, 0ull, 0ull, 14411518807585587200ull}},
    {{0ull, 0ull, 0ull, 18014398509481984000ull}},
    {{0ull, 0ull, 0ull, 11258999068426240000ull}},
    {{0ull, 0ull, 0ull, 14073748835532800000ull}},
    {{0ull, 0ull, 0ull, 17592186044416000000ull}},
    {{0ull, 0ull, 0ull, 10995116277760000000ull}},
    {{0ull, 0ull, 0ull, 13743895347200000000ull}},
    {{0ull, 0ull, 0ull, 17179869184000000000ull}},
    {{0ull, 0ull, 0ull, 10737418240000000000ull}},
    {{0ull, 0ull, 0ull, 13421772800000000000ull}},
    {{0ull, 0ull, 0ull, 16777216000000000000ull}},
    {{0ull, 0ull, 0ull, 10485760000000000000ull}},
    {{0ull, 0ull, 0ull, 13107200000000000000ull}},
    {{0ull, 0ull, 0ull, 16384000000000000000ull}},
    {{0ull, 0ull, 0ull, 10240000000000000000ull}},
    {{0ull, 0ull, 0ull, 12800000000000000000ull}},
    {{0ull, 0ull, 0ull, 16000000000000000000ull}},
    {{0ull, 0ull, 0ull, 10000000000000000000ull}},
    {{0ull, 0ull, 0ull, 12500000000000000000ull}},
    {{0ull, 0ull, 0ull, 15625000000000000000ull}},
    {{0ull, 0ull, 0ull, 9765625000000000000ull}},
    {{0ull, 0ull, 0ull, 12207031250000000000ull}},
    {{0ull, 0ull, 0ull, 15258789062500000000ull}},
    {{0ull, 0ull, 0ull, 9536743164062500000ull}},
    {{0ull, 0ull, 0ull, 11920928955078125000ull}},
    {{0ull, 0ull, 0ull, 14901161193847656250ull}},
    {{0ull, 0ull, 4611686018427387904ull, 9313225746154785156ull}},
    {{0ull, 0ull, 5764607523034234880ull, 11641532182693481445ull}},
    {{0ull, 0ull, 11817445422220181504ull, 14551915228366851806ull}},
    {{0ull, 0ull, 5548434740920451072ull, 18189894035458564758ull}},
    {{0ull, 0ull, 17302829768357445632ull, 11368683772161602973ull}},
    {{0ull, 0ull, 7793479155164643328ull, 14210854715202003717ull}},
    {{0ull, 0ull, 14353534962383192064ull, 17763568394002504646ull}},
    {{0ull, 0ull, 4359273333062107136ull, 11102230246251565404ull}},
    {{0ull, 0ull, 5449091666327633920ull, 13877787807814456755ull}},
    {{0ull, 0ull, 2199678564482154496ull, 17347234759768070944ull}},
    {{0ull, 0ull, 1374799102801346560ull, 10842021724855044340ull}},
    {{0ull, 0ull, 1718498878501683200ull, 13552527156068805425ull}},
    {{0ull, 0ull, 6759809616554491904ull, 16940658945086006781ull}},
    {{0ull, 0ull, 6530724019560251392ull, 10587911840678754238ull}},
    {{0ull, 0ull, 17386777061305090048ull, 13234889800848442797ull}},
    {{0ull, 0ull, 7898413271349198848ull, 16543612251060553497ull}},
    {{0ull, 0ull, 16465723340661719040ull, 10339757656912845935ull}},
    {{0ull, 0ull, 15970468157399760896ull, 12924697071141057419ull}},
    {{0ull, 0ull, 15351399178322313216ull, 16155871338926321774ull}},
    {{0ull, 0ull, 4982938468024057856ull, 10097419586828951109ull}},
    {{0ull, 0ull, 10840359103457460224ull, 12621774483536188886ull}},
    {{0ull, 0ull, 4327076842467049472ull, 15777218104420236108ull}},
    {{0ull, 0ull, 11927795063396681728ull, 9860761315262647567ull}},
    {{0ull, 0ull, 10298057810818464256ull, 12325951644078309459ull}},
    {{0ull, 0ull, 8260886245095692416ull, 15407439555097886824ull}},
    {{0ull, 0ull, 5163053903184807760ull, 9629649721936179265ull}},
    {{0ull, 0ull, 11065503397408397604ull, 12037062152420224081ull}},
    {{0ull, 0ull, 18443565265187884909ull, 15046327690525280101ull}},
    {{0ull, 2305843009213693952ull, 13833071299956122020ull, 9403954806578300063ull}},
    {{0ull, 2882303761517117440ull, 12679653106517764621ull, 11754943508222875079ull}},
    {{0ull, 8214565720323784704ull, 11237880364719817872ull, 14693679385278593849ull}},
    {{0ull, 10268207150404730880ull, 212292400617608628ull, 18367099231598242312ull}},
    {{0ull, 15641001505857732608ull, 132682750386005392ull, 11479437019748901445ull}},
    {{0ull, 1104507808612614144ull, 4777539456409894645ull, 14349296274686126806ull}},
    {{0ull, 5992320779193155584ull, 15195296357367144114ull, 17936620343357658507ull}},
    {{0ull, 8356886505423110144ull, 7191217214140771119ull, 11210387714598536567ull}}};

static const int bid_outertable_exp[] = {
    -16839, -16413, -15988, -15563, -15138, -14713, -14287, -13862, -13437, -13012, -12586, -12161, -11736, -11311,
    -10886, -10460, -10035, -9610,  -9185,  -8760,  -8334,  -7909,  -7484,  -7059,  -6634,  -6208,  -5783,  -5358,
    -4933,  -4508,  -4082,  -3657,  -3232,  -2807,  -2382,  -1956,  -1531,  -1106,  -681,   -255,   170,    595,
    1020,   1445,   1871,   2296,   2721,   3146,   3571,   3997,   4422,   4847,   5272,   5697,   6123,   6548,
    6973,   7398,   7823,   8249,   8674,   9099,   9524,   9949,   10375,  10800,  11225,  11650,  12075,  12501,
    12926,  13351,  13776,  14202,  14627,  15052,  15477,  15902,  16328,  16753,
};

static const int bid_innertable_exp[] = {
    -468, -465, -461, -458, -455, -451, -448, -445, -442, -438, -435, -432, -428, -425, -422, -418, -415, -412, -408,
    -405, -402, -398, -395, -392, -388, -385, -382, -378, -375, -372, -368, -365, -362, -358, -355, -352, -349, -345,
    -342, -339, -335, -332, -329, -325, -322, -319, -315, -312, -309, -305, -302, -299, -295, -292, -289, -285, -282,
    -279, -275, -272, -269, -265, -262, -259, -255, -252, -249, -246, -242, -239, -236, -232, -229, -226, -222, -219,
    -216, -212, -209, -206, -202, -199, -196, -192, -189, -186, -182, -179, -176, -172, -169, -166, -162, -159, -156,
    -153, -149, -146, -143, -139, -136, -133, -129, -126, -123, -119, -116, -113, -109, -106, -103, -99,  -96,  -93,
    -89,  -86,  -83,  -79,  -76,  -73,  -69,  -66,  -63,  -60,  -56,  -53,  -50,  -46,
};

void realm_binary64_to_bid128(BID_UINT128* pres, double* px, _IDEC_flags* pfpsf)
{
    double x = *px;
    BID_UINT128 c;
    BID_UINT64 c_prov_hi, c_prov_lo;
    BID_UINT256 r;
    BID_UINT384 z;

    // Unpack the input
    int e, s, t, e_out, e_plus, e_hi, e_lo, f;
    {
        union {
            BID_UINT64 i;
            double f;
        } x_in;
        x_in.f = x;
        c.w[1] = x_in.i;
        e = (c.w[1] >> 52) & ((1ull << 11) - 1);
        s = c.w[1] >> 63;
        c.w[1] = c.w[1] & ((1ull << 52) - 1);
        if (e == 0) {
            int l;
            if (c.w[1] == 0) {
                BID_UINT128 x_out;
                x_out.w[0] = 0;
                x_out.w[1] = ((BID_UINT64)(s) << 63) + ((BID_UINT64)(6176) << 49) + (0);
                *pres = x_out;
                return;
            };
            l = (((c.w[1]) == 0)
                     ? 64
                     : (((((c.w[1]) & 0xFFFFFFFF00000000ull) <= ((c.w[1]) & ~0xFFFFFFFF00000000ull)) ? 32 : 0) +
                        ((((c.w[1]) & 0xFFFF0000FFFF0000ull) <= ((c.w[1]) & ~0xFFFF0000FFFF0000ull)) ? 16 : 0) +
                        ((((c.w[1]) & 0xFF00FF00FF00FF00ull) <= ((c.w[1]) & ~0xFF00FF00FF00FF00ull)) ? 8 : 0) +
                        ((((c.w[1]) & 0xF0F0F0F0F0F0F0F0ull) <= ((c.w[1]) & ~0xF0F0F0F0F0F0F0F0ull)) ? 4 : 0) +
                        ((((c.w[1]) & 0xCCCCCCCCCCCCCCCCull) <= ((c.w[1]) & ~0xCCCCCCCCCCCCCCCCull)) ? 2 : 0) +
                        ((((c.w[1]) & 0xAAAAAAAAAAAAAAAAull) <= ((c.w[1]) & ~0xAAAAAAAAAAAAAAAAull)) ? 1 : 0))) -
                (64 - 53);
            c.w[1] = c.w[1] << l;
            e = -(l + 1074);
            t = 0;
            *(pfpsf) |= 0x02;
        }
        else if (e == ((1ull << 11) - 1)) {
            if (c.w[1] == 0) {
                BID_UINT128 x_out;
                x_out.w[0] = 0;
                x_out.w[1] = ((BID_UINT64)(s) << 63) + ((BID_UINT64)((0xF << 10)) << 49) + (0);
                *pres = x_out;
                return;
            };
            if ((c.w[1] & (1ull << 51)) == 0)
                *(pfpsf) |= 0x01;
            {
                if ((((54210108624275ull) < (((((unsigned long long)c.w[1]) << 13) >> 18))) ||
                     (((54210108624275ull) == (((((unsigned long long)c.w[1]) << 13) >> 18))) &&
                      ((4089650035136921599ull) <
                       (((0ull >> 18) + ((((unsigned long long)c.w[1]) << 13) << 46))))))) {
                    BID_UINT128 x_out;
                    x_out.w[0] = 0ull;
                    x_out.w[1] = ((BID_UINT64)(s) << 63) + ((BID_UINT64)((0x1F << 9)) << 49) + (0ull);
                    *pres = x_out;
                    return;
                }
                else {
                    BID_UINT128 x_out;
                    x_out.w[0] = ((0ull >> 18) + ((((unsigned long long)c.w[1]) << 13) << 46));
                    x_out.w[1] = ((BID_UINT64)(s) << 63) + ((BID_UINT64)((0x1F << 9)) << 49) +
                                 (((((unsigned long long)c.w[1]) << 13) >> 18));
                    *pres = x_out;
                    return;
                }
            }
        }
        else {
            c.w[1] += 1ull << 52;
            t = (((c.w[1]) == 0) ? 64
                                 : (((((c.w[1]) & -(c.w[1])) & ~0xFFFFFFFF00000000ull) ? 0 : 32) +
                                    ((((c.w[1]) & -(c.w[1])) & ~0xFFFF0000FFFF0000ull) ? 0 : 16) +
                                    ((((c.w[1]) & -(c.w[1])) & ~0xFF00FF00FF00FF00ull) ? 0 : 8) +
                                    ((((c.w[1]) & -(c.w[1])) & ~0xF0F0F0F0F0F0F0F0ull) ? 0 : 4) +
                                    ((((c.w[1]) & -(c.w[1])) & ~0xCCCCCCCCCCCCCCCCull) ? 0 : 2) +
                                    ((((c.w[1]) & -(c.w[1])) & ~0xAAAAAAAAAAAAAAAAull) ? 0 : 1)));
            e -= 1075;
        }
    };

    // Now -1126<=e<=971 (971 for max normal, -1074 for min normal, -1126 for min denormal)

    // Shift up to the top: like a pure quad coefficient with a shift of 15.
    // In our case, this is 2^{113-53+15} times the core, so unpack at the
    // high end shifted by 11.

    c.w[0] = 0;
    c.w[1] = c.w[1] << 11;

    t += (113 - 53);
    e -= (113 - 53); // Now e belongs [-1186;911].

    // (We never need to check for overflow: this format is the biggest of all!)

    // Now filter out all the exact cases where we need to specially force
    // the exponent to 0. We can let through inexact cases and those where the
    // main path will do the right thing anyway, e.g. integers outside coeff range.
    //
    // First check that e <= 0, because if e > 0, the input must be >= 2^113,
    // which is too large for the coefficient of any target decimal format.
    // We write a = -(e + t)
    //
    // (1) If e + t >= 0 <=> a <= 0 the input is an integer; treat it specially
    //     iff it fits in the coefficient range. Shift c' = c >> -e, and
    //     compare with the coefficient range; if it's in range then c' is
    //     our coefficient, exponent is 0. Otherwise we pass through.
    //
    // (2) If a > 0 then we have a non-integer input. The special case would
    //     arise as c' / 2^a where c' = c >> t, i.e. 10^-a * (5^a c'). Now
    //     if a > 48 we can immediately forget this, since 5^49 > 10^34.
    //     Otherwise we determine whether we're in range by a table based on
    //     a, and if so get the multiplier also from a table based on a.
    //
    // Note that when we shift, we need to take into account the fact that
    // c is already 15 places to the left in preparation for the reciprocal
    // multiplication; thus we add 15 to all the shift counts

    if (e <= 0) {
        BID_UINT128 cint;
        int a = -(e + t);
        cint.w[1] = c.w[1], cint.w[0] = c.w[0];
        if (a <= 0) {
            (((15 - e) == 0)
             ? cint.w[1] = cint.w[1],
             cint.w[0] = cint.w[0]
             : (((15 - e) >= 64) ? cint.w[0] = cint.w[1] >> ((15 - e) - 64), cint.w[1] = 0
                                 : ((cint.w[0]) = ((cint.w[1]) << (64 - (15 - e))) + ((cint.w[0]) >> (15 - e)),
                                    (cint.w[1]) = (cint.w[1]) >> (15 - e))));
            if ((((cint.w[1]) < (542101086242752ull)) ||
                 (((cint.w[1]) == (542101086242752ull)) && ((cint.w[0]) < (4003012203950112768ull))))) {
                BID_UINT128 x_out;
                x_out.w[0] = cint.w[0];
                x_out.w[1] = ((BID_UINT64)(s) << 63) + ((BID_UINT64)(6176) << 49) + (cint.w[1]);
                *pres = x_out;
                return;
            };
        }
        else if (a <= 48) {
            BID_UINT128 pow5 = bid_coefflimits_bid128[a];
            (((15 + t) == 0)
             ? cint.w[1] = cint.w[1],
             cint.w[0] = cint.w[0]
             : (((15 + t) >= 64) ? cint.w[0] = cint.w[1] >> ((15 + t) - 64), cint.w[1] = 0
                                 : ((cint.w[0]) = ((cint.w[1]) << (64 - (15 + t))) + ((cint.w[0]) >> (15 + t)),
                                    (cint.w[1]) = (cint.w[1]) >> (15 + t))));
            if ((((cint.w[1]) < (pow5.w[1])) || (((cint.w[1]) == (pow5.w[1])) && ((cint.w[0]) <= (pow5.w[0]))))) {
                BID_UINT128 cc;
                cc.w[1] = cint.w[1];
                cc.w[0] = cint.w[0];
                pow5 = bid_power_five[a];
                {
                    BID_UINT128 ALBL;
                    BID_UINT64 QM64;
                    {
                        BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                        CXH = ((cc).w[0]) >> 32;
                        CXL = (BID_UINT32)((cc).w[0]);
                        CYH = ((pow5).w[0]) >> 32;
                        CYL = (BID_UINT32)((pow5).w[0]);
                        PM = CXH * CYL;
                        PH = CXH * CYH;
                        PL = CXL * CYL;
                        PM2 = CXL * CYH;
                        PH += (PM >> 32);
                        PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                        (ALBL).w[1] = PH + (PM >> 32);
                        (ALBL).w[0] = (PM << 32) + (BID_UINT32)PL;
                    };
                    QM64 = (pow5).w[0] * (cc).w[1] + (cc).w[0] * (pow5).w[1];
                    (cc).w[0] = ALBL.w[0];
                    (cc).w[1] = QM64 + ALBL.w[1];
                };
                {
                    BID_UINT128 x_out;
                    x_out.w[0] = cc.w[0];
                    x_out.w[1] = ((BID_UINT64)(s) << 63) + ((BID_UINT64)(6176 - a) << 49) + (cc.w[1]);
                    *pres = x_out;
                    return;
                };
            }
        }
    }

    // Input exponent can stretch between the maximal and minimal
    // exponents (remembering we force normalization): -16607 <= e <= 16271

    // Compute the estimated decimal exponent e_out; the provisional exponent
    // will be either "e_out" or "e_out-1" depending on later significand check
    // NB: this is the *biased* exponent
    e_plus = e + 42152;
    e_out = (((19728 * e_plus) + ((19779 * e_plus) >> 16)) >> 16) - 6512;

    // Set up pointers into the bipartite table
    e_hi = 11232 - e_out;
    e_lo = e_hi & 127;
    e_hi = e_hi >> 7;

    // Look up the inner entry first
    r = bid_innertable_sig[e_lo], f = bid_innertable_exp[e_lo];

    // If we need the other entry, multiply significands and add exponents
    if (e_hi != 39) {
        BID_UINT256 s_prime = bid_outertable_sig[e_hi];
        BID_UINT512 t_prime;
        f = f + 256 + bid_outertable_exp[e_hi];
        {
            BID_UINT512 P0, P1, P2, P3;
            BID_UINT64 CY;
            {
                BID_UINT128 lP0, lP1, lP2, lP3;
                BID_UINT64 lC;
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[0]) >> 32;
                    CXL = (BID_UINT32)((r).w[0]);
                    CYH = ((s_prime).w[0]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[0]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP0).w[1] = PH + (PM >> 32);
                    (lP0).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[0]) >> 32;
                    CXL = (BID_UINT32)((r).w[0]);
                    CYH = ((s_prime).w[1]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[1]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP1).w[1] = PH + (PM >> 32);
                    (lP1).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[0]) >> 32;
                    CXL = (BID_UINT32)((r).w[0]);
                    CYH = ((s_prime).w[2]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[2]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP2).w[1] = PH + (PM >> 32);
                    (lP2).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[0]) >> 32;
                    CXL = (BID_UINT32)((r).w[0]);
                    CYH = ((s_prime).w[3]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[3]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP3).w[1] = PH + (PM >> 32);
                    (lP3).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                (P0).w[0] = lP0.w[0];
                {
                    BID_UINT64 X1 = lP1.w[0];
                    (P0).w[1] = lP1.w[0] + lP0.w[1];
                    lC = ((P0).w[1] < X1) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP2.w[0] + lC;
                    (P0).w[2] = X1 + lP1.w[1];
                    lC = (((P0).w[2] < X1) || (X1 < lC)) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP3.w[0] + lC;
                    (P0).w[3] = X1 + lP2.w[1];
                    lC = (((P0).w[3] < X1) || (X1 < lC)) ? 1 : 0;
                };
                (P0).w[4] = lP3.w[1] + lC;
            };
            {
                BID_UINT128 lP0, lP1, lP2, lP3;
                BID_UINT64 lC;
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[1]) >> 32;
                    CXL = (BID_UINT32)((r).w[1]);
                    CYH = ((s_prime).w[0]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[0]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP0).w[1] = PH + (PM >> 32);
                    (lP0).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[1]) >> 32;
                    CXL = (BID_UINT32)((r).w[1]);
                    CYH = ((s_prime).w[1]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[1]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP1).w[1] = PH + (PM >> 32);
                    (lP1).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[1]) >> 32;
                    CXL = (BID_UINT32)((r).w[1]);
                    CYH = ((s_prime).w[2]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[2]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP2).w[1] = PH + (PM >> 32);
                    (lP2).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[1]) >> 32;
                    CXL = (BID_UINT32)((r).w[1]);
                    CYH = ((s_prime).w[3]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[3]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP3).w[1] = PH + (PM >> 32);
                    (lP3).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                (P1).w[0] = lP0.w[0];
                {
                    BID_UINT64 X1 = lP1.w[0];
                    (P1).w[1] = lP1.w[0] + lP0.w[1];
                    lC = ((P1).w[1] < X1) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP2.w[0] + lC;
                    (P1).w[2] = X1 + lP1.w[1];
                    lC = (((P1).w[2] < X1) || (X1 < lC)) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP3.w[0] + lC;
                    (P1).w[3] = X1 + lP2.w[1];
                    lC = (((P1).w[3] < X1) || (X1 < lC)) ? 1 : 0;
                };
                (P1).w[4] = lP3.w[1] + lC;
            };
            {
                BID_UINT128 lP0, lP1, lP2, lP3;
                BID_UINT64 lC;
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[2]) >> 32;
                    CXL = (BID_UINT32)((r).w[2]);
                    CYH = ((s_prime).w[0]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[0]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP0).w[1] = PH + (PM >> 32);
                    (lP0).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[2]) >> 32;
                    CXL = (BID_UINT32)((r).w[2]);
                    CYH = ((s_prime).w[1]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[1]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP1).w[1] = PH + (PM >> 32);
                    (lP1).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[2]) >> 32;
                    CXL = (BID_UINT32)((r).w[2]);
                    CYH = ((s_prime).w[2]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[2]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP2).w[1] = PH + (PM >> 32);
                    (lP2).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[2]) >> 32;
                    CXL = (BID_UINT32)((r).w[2]);
                    CYH = ((s_prime).w[3]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[3]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP3).w[1] = PH + (PM >> 32);
                    (lP3).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                (P2).w[0] = lP0.w[0];
                {
                    BID_UINT64 X1 = lP1.w[0];
                    (P2).w[1] = lP1.w[0] + lP0.w[1];
                    lC = ((P2).w[1] < X1) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP2.w[0] + lC;
                    (P2).w[2] = X1 + lP1.w[1];
                    lC = (((P2).w[2] < X1) || (X1 < lC)) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP3.w[0] + lC;
                    (P2).w[3] = X1 + lP2.w[1];
                    lC = (((P2).w[3] < X1) || (X1 < lC)) ? 1 : 0;
                };
                (P2).w[4] = lP3.w[1] + lC;
            };
            {
                BID_UINT128 lP0, lP1, lP2, lP3;
                BID_UINT64 lC;
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[3]) >> 32;
                    CXL = (BID_UINT32)((r).w[3]);
                    CYH = ((s_prime).w[0]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[0]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP0).w[1] = PH + (PM >> 32);
                    (lP0).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[3]) >> 32;
                    CXL = (BID_UINT32)((r).w[3]);
                    CYH = ((s_prime).w[1]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[1]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP1).w[1] = PH + (PM >> 32);
                    (lP1).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[3]) >> 32;
                    CXL = (BID_UINT32)((r).w[3]);
                    CYH = ((s_prime).w[2]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[2]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP2).w[1] = PH + (PM >> 32);
                    (lP2).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                {
                    BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                    CXH = ((r).w[3]) >> 32;
                    CXL = (BID_UINT32)((r).w[3]);
                    CYH = ((s_prime).w[3]) >> 32;
                    CYL = (BID_UINT32)((s_prime).w[3]);
                    PM = CXH * CYL;
                    PH = CXH * CYH;
                    PL = CXL * CYL;
                    PM2 = CXL * CYH;
                    PH += (PM >> 32);
                    PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                    (lP3).w[1] = PH + (PM >> 32);
                    (lP3).w[0] = (PM << 32) + (BID_UINT32)PL;
                };
                (P3).w[0] = lP0.w[0];
                {
                    BID_UINT64 X1 = lP1.w[0];
                    (P3).w[1] = lP1.w[0] + lP0.w[1];
                    lC = ((P3).w[1] < X1) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP2.w[0] + lC;
                    (P3).w[2] = X1 + lP1.w[1];
                    lC = (((P3).w[2] < X1) || (X1 < lC)) ? 1 : 0;
                };
                {
                    BID_UINT64 X1;
                    X1 = lP3.w[0] + lC;
                    (P3).w[3] = X1 + lP2.w[1];
                    lC = (((P3).w[3] < X1) || (X1 < lC)) ? 1 : 0;
                };
                (P3).w[4] = lP3.w[1] + lC;
            };
            (t_prime).w[0] = P0.w[0];
            {
                BID_UINT64 X1 = P1.w[0];
                (t_prime).w[1] = P1.w[0] + P0.w[1];
                CY = ((t_prime).w[1] < X1) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P1.w[1] + CY;
                (t_prime).w[2] = X1 + P0.w[2];
                CY = (((t_prime).w[2] < X1) || (X1 < CY)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P1.w[2] + CY;
                (t_prime).w[3] = X1 + P0.w[3];
                CY = (((t_prime).w[3] < X1) || (X1 < CY)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P1.w[3] + CY;
                (t_prime).w[4] = X1 + P0.w[4];
                CY = (((t_prime).w[4] < X1) || (X1 < CY)) ? 1 : 0;
            };
            (t_prime).w[5] = P1.w[4] + CY;
            {
                BID_UINT64 X1 = P2.w[0];
                (t_prime).w[2] = P2.w[0] + (t_prime).w[2];
                CY = ((t_prime).w[2] < X1) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P2.w[1] + CY;
                (t_prime).w[3] = X1 + (t_prime).w[3];
                CY = (((t_prime).w[3] < X1) || (X1 < CY)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P2.w[2] + CY;
                (t_prime).w[4] = X1 + (t_prime).w[4];
                CY = (((t_prime).w[4] < X1) || (X1 < CY)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P2.w[3] + CY;
                (t_prime).w[5] = X1 + (t_prime).w[5];
                CY = (((t_prime).w[5] < X1) || (X1 < CY)) ? 1 : 0;
            };
            (t_prime).w[6] = P2.w[4] + CY;
            {
                BID_UINT64 X1 = P3.w[0];
                (t_prime).w[3] = P3.w[0] + (t_prime).w[3];
                CY = ((t_prime).w[3] < X1) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P3.w[1] + CY;
                (t_prime).w[4] = X1 + (t_prime).w[4];
                CY = (((t_prime).w[4] < X1) || (X1 < CY)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P3.w[2] + CY;
                (t_prime).w[5] = X1 + (t_prime).w[5];
                CY = (((t_prime).w[5] < X1) || (X1 < CY)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = P3.w[3] + CY;
                (t_prime).w[6] = X1 + (t_prime).w[6];
                CY = (((t_prime).w[6] < X1) || (X1 < CY)) ? 1 : 0;
            };
            (t_prime).w[7] = P3.w[4] + CY;
        };
        r.w[0] = t_prime.w[4] + 1, r.w[1] = t_prime.w[5], r.w[2] = t_prime.w[6], r.w[3] = t_prime.w[7];
    }

    {
        BID_UINT512 P0, P1;
        BID_UINT64 CY;
        {
            BID_UINT128 lP0, lP1, lP2, lP3;
            BID_UINT64 lC;
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[0]) >> 32;
                CXL = (BID_UINT32)((c).w[0]);
                CYH = ((r).w[0]) >> 32;
                CYL = (BID_UINT32)((r).w[0]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP0).w[1] = PH + (PM >> 32);
                (lP0).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[0]) >> 32;
                CXL = (BID_UINT32)((c).w[0]);
                CYH = ((r).w[1]) >> 32;
                CYL = (BID_UINT32)((r).w[1]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP1).w[1] = PH + (PM >> 32);
                (lP1).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[0]) >> 32;
                CXL = (BID_UINT32)((c).w[0]);
                CYH = ((r).w[2]) >> 32;
                CYL = (BID_UINT32)((r).w[2]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP2).w[1] = PH + (PM >> 32);
                (lP2).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[0]) >> 32;
                CXL = (BID_UINT32)((c).w[0]);
                CYH = ((r).w[3]) >> 32;
                CYL = (BID_UINT32)((r).w[3]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP3).w[1] = PH + (PM >> 32);
                (lP3).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            (P0).w[0] = lP0.w[0];
            {
                BID_UINT64 X1 = lP1.w[0];
                (P0).w[1] = lP1.w[0] + lP0.w[1];
                lC = ((P0).w[1] < X1) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = lP2.w[0] + lC;
                (P0).w[2] = X1 + lP1.w[1];
                lC = (((P0).w[2] < X1) || (X1 < lC)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = lP3.w[0] + lC;
                (P0).w[3] = X1 + lP2.w[1];
                lC = (((P0).w[3] < X1) || (X1 < lC)) ? 1 : 0;
            };
            (P0).w[4] = lP3.w[1] + lC;
        };
        {
            BID_UINT128 lP0, lP1, lP2, lP3;
            BID_UINT64 lC;
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[1]) >> 32;
                CXL = (BID_UINT32)((c).w[1]);
                CYH = ((r).w[0]) >> 32;
                CYL = (BID_UINT32)((r).w[0]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP0).w[1] = PH + (PM >> 32);
                (lP0).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[1]) >> 32;
                CXL = (BID_UINT32)((c).w[1]);
                CYH = ((r).w[1]) >> 32;
                CYL = (BID_UINT32)((r).w[1]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP1).w[1] = PH + (PM >> 32);
                (lP1).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[1]) >> 32;
                CXL = (BID_UINT32)((c).w[1]);
                CYH = ((r).w[2]) >> 32;
                CYL = (BID_UINT32)((r).w[2]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP2).w[1] = PH + (PM >> 32);
                (lP2).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            {
                BID_UINT64 CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
                CXH = ((c).w[1]) >> 32;
                CXL = (BID_UINT32)((c).w[1]);
                CYH = ((r).w[3]) >> 32;
                CYL = (BID_UINT32)((r).w[3]);
                PM = CXH * CYL;
                PH = CXH * CYH;
                PL = CXL * CYL;
                PM2 = CXL * CYH;
                PH += (PM >> 32);
                PM = (BID_UINT64)((BID_UINT32)PM) + PM2 + (PL >> 32);
                (lP3).w[1] = PH + (PM >> 32);
                (lP3).w[0] = (PM << 32) + (BID_UINT32)PL;
            };
            (P1).w[0] = lP0.w[0];
            {
                BID_UINT64 X1 = lP1.w[0];
                (P1).w[1] = lP1.w[0] + lP0.w[1];
                lC = ((P1).w[1] < X1) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = lP2.w[0] + lC;
                (P1).w[2] = X1 + lP1.w[1];
                lC = (((P1).w[2] < X1) || (X1 < lC)) ? 1 : 0;
            };
            {
                BID_UINT64 X1;
                X1 = lP3.w[0] + lC;
                (P1).w[3] = X1 + lP2.w[1];
                lC = (((P1).w[3] < X1) || (X1 < lC)) ? 1 : 0;
            };
            (P1).w[4] = lP3.w[1] + lC;
        };
        (z).w[0] = P0.w[0];
        {
            BID_UINT64 X1 = P1.w[0];
            (z).w[1] = P1.w[0] + P0.w[1];
            CY = ((z).w[1] < X1) ? 1 : 0;
        };
        {
            BID_UINT64 X1;
            X1 = P1.w[1] + CY;
            (z).w[2] = X1 + P0.w[2];
            CY = (((z).w[2] < X1) || (X1 < CY)) ? 1 : 0;
        };
        {
            BID_UINT64 X1;
            X1 = P1.w[2] + CY;
            (z).w[3] = X1 + P0.w[3];
            CY = (((z).w[3] < X1) || (X1 < CY)) ? 1 : 0;
        };
        {
            BID_UINT64 X1;
            X1 = P1.w[3] + CY;
            (z).w[4] = X1 + P0.w[4];
            CY = (((z).w[4] < X1) || (X1 < CY)) ? 1 : 0;
        };
        (z).w[5] = P1.w[4] + CY;
    };

    // Make adjustive shift, ignoring the lower 128 bits
    e = -(241 + e + f);
    ((z.w[0]) = ((z.w[1]) << (64 - (e))) + ((z.w[0]) >> (e)), (z.w[1]) = ((z.w[2]) << (64 - (e))) + ((z.w[1]) >> (e)),
     (z.w[2]) = ((z.w[3]) << (64 - (e))) + ((z.w[2]) >> (e)), (z.w[3]) = ((z.w[4]) << (64 - (e))) + ((z.w[3]) >> (e)),
     (z.w[4]) = ((z.w[5]) << (64 - (e))) + ((z.w[4]) >> (e)), (z.w[5]) = (z.w[5]) >> (e));

    // Now test against 10^33 and so decide on adjustment
    // I feel there ought to be a smarter way of doing the multiplication
    if ((((z.w[5]) < (54210108624275ull)) ||
         (((z.w[5]) == (54210108624275ull)) && ((z.w[4]) < (4089650035136921600ull))))) {
        {
            unsigned long long c0, c1, c2, c3, c4, c5;
            {
                unsigned long long s3 = (z.w[0]) + ((z.w[0]) >> 2);
                (c0) = ((s3 < (unsigned long long)(z.w[0])) << 3) + (s3 >> 61);
                s3 = (s3 << 3) + ((z.w[0] & 3) << 1);
                (z.w[0]) = s3 + (0ull);
                if ((unsigned long long)(z.w[0]) < s3)
                    ++(c0);
            };
            {
                unsigned long long s3 = (z.w[1]) + ((z.w[1]) >> 2);
                (c1) = ((s3 < (unsigned long long)(z.w[1])) << 3) + (s3 >> 61);
                s3 = (s3 << 3) + ((z.w[1] & 3) << 1);
                (z.w[1]) = s3 + (c0);
                if ((unsigned long long)(z.w[1]) < s3)
                    ++(c1);
            };
            {
                unsigned long long s3 = (z.w[2]) + ((z.w[2]) >> 2);
                (c2) = ((s3 < (unsigned long long)(z.w[2])) << 3) + (s3 >> 61);
                s3 = (s3 << 3) + ((z.w[2] & 3) << 1);
                (z.w[2]) = s3 + (c1);
                if ((unsigned long long)(z.w[2]) < s3)
                    ++(c2);
            };
            {
                unsigned long long s3 = (z.w[3]) + ((z.w[3]) >> 2);
                (c3) = ((s3 < (unsigned long long)(z.w[3])) << 3) + (s3 >> 61);
                s3 = (s3 << 3) + ((z.w[3] & 3) << 1);
                (z.w[3]) = s3 + (c2);
                if ((unsigned long long)(z.w[3]) < s3)
                    ++(c3);
            };
            {
                unsigned long long s3 = (z.w[4]) + ((z.w[4]) >> 2);
                (c4) = ((s3 < (unsigned long long)(z.w[4])) << 3) + (s3 >> 61);
                s3 = (s3 << 3) + ((z.w[4] & 3) << 1);
                (z.w[4]) = s3 + (c3);
                if ((unsigned long long)(z.w[4]) < s3)
                    ++(c4);
            };
            {
                unsigned long long s3 = (z.w[5]) + ((z.w[5]) >> 2);
                (c5) = ((s3 < (unsigned long long)(z.w[5])) << 3) + (s3 >> 61);
                s3 = (s3 << 3) + ((z.w[5] & 3) << 1);
                (z.w[5]) = s3 + (c4);
                if ((unsigned long long)(z.w[5]) < s3)
                    ++(c5);
            };
        };
        e_out = e_out - 1;
    }

    // Set up provisional results
    c_prov_hi = z.w[5];
    c_prov_lo = z.w[4];

    // Round using round-sticky words
    // If we spill over into the next decade, correct
    if ((((bid_roundbound_128[(__bid_IDEC_glbround << 2) + ((s & 1) << 1) + (c_prov_lo & 1)].w[1]) < (z.w[3])) ||
         (((bid_roundbound_128[(__bid_IDEC_glbround << 2) + ((s & 1) << 1) + (c_prov_lo & 1)].w[1]) == (z.w[3])) &&
          ((bid_roundbound_128[(__bid_IDEC_glbround << 2) + ((s & 1) << 1) + (c_prov_lo & 1)].w[0]) < (z.w[2]))))


    ) {
        c_prov_lo = c_prov_lo + 1;
        if (c_prov_lo == 0)
            c_prov_hi = c_prov_hi + 1;
        else if ((c_prov_lo == 4003012203950112768ull) && (c_prov_hi == 542101086242752ull)) {
            c_prov_hi = 54210108624275ull;
            c_prov_lo = 4089650035136921600ull;
            e_out = e_out + 1;
        }
    }

    // Don't need to check overflow or underflow; however set inexact flag
    if ((z.w[3] != 0) || (z.w[2] != 0))
        *(pfpsf) |= 0x20;

    // Package up the result
    {
        BID_UINT128 x_out;
        x_out.w[0] = c_prov_lo;
        x_out.w[1] = ((BID_UINT64)(s) << 63) + ((BID_UINT64)(e_out) << 49) + (c_prov_hi);
        *pres = x_out;
        return;
    };
}

} // namespace

/*******************************************************************************************************************/

Decimal128::Decimal128(double val, RoundTo rounding_precision) noexcept
{
    // The logic below is ported from MongoDB Decimal128 implementation
    uint64_t largest_coeff = (rounding_precision == RoundTo::Digits7) ? 9999999 : 999999999999999;
    unsigned flags = 0;
    BID_UINT128 converted_value;
    realm_binary64_to_bid128(&converted_value, &val, &flags);
    memcpy(this, &converted_value, sizeof(*this));

    // If the precision is already less than 15 decimals, or val is infinity or NaN, there's no need to quantize
    if ((get_coefficient_low() <= largest_coeff && get_coefficient_high() == 0) || std::isinf(val) ||
        std::isnan(val)) {
        return;
    }

    // Get the base2 exponent from val.
    int base2Exp;
    frexp(val, &base2Exp);

    // As frexp normalizes val between 0.5 and 1.0 rather than 1.0 and 2.0, adjust.
    base2Exp--;


    // We will use base10Exp = base2Exp * 30103 / (100*1000) as lowerbound (using integer division).
    //
    // This formula is derived from the following, with base2Exp the binary exponent of val:
    //   (1) 10**(base2Exp * log10(2)) == 2**base2Exp
    //   (2) 0.30103 closely approximates log10(2)
    //
    // Exhaustive testing using Python shows :
    //     { base2Exp * 30103 / (100 * 1000) == math.floor(math.log10(2**base2Exp))
    //       for base2Exp in xrange(-1074, 1023) } == { True }
    int base10Exp = (base2Exp * 30103) / (100 * 1000);

    // As integer division truncates, rather than rounds down (as in Python), adjust accordingly.
    if (base2Exp < 0)
        base10Exp--;

    int adjust = (rounding_precision == RoundTo::Digits7) ? 6 : 14;
    BID_UINT128 q{1, BID_UINT64(base10Exp - adjust + DECIMAL_EXPONENT_BIAS_128) << DECIMAL_COEFF_HIGH_BITS};
    BID_UINT128 quantizedResult;
    bid128_quantize(&quantizedResult, &converted_value, &q, &flags);
    memcpy(this, &quantizedResult, sizeof(*this));

    // Check if the quantization was done correctly: m_valuem_value stores exactly 15
    // decimal digits of precision (15 digits can fit into the low 64 bits of the decimal)
    if (get_coefficient_low() > largest_coeff) {
        // If we didn't precisely get 15 digits of precision, the original base 10 exponent
        // guess was 1 off, so quantize once more with base10Exp + 1
        adjust--;
        BID_UINT128 q1{1, (BID_UINT64(base10Exp) - adjust + DECIMAL_EXPONENT_BIAS_128) << DECIMAL_COEFF_HIGH_BITS};
        bid128_quantize(&quantizedResult, &converted_value, &q1, &flags);
        memcpy(this, &quantizedResult, sizeof(*this));
    }
}

Decimal128::Decimal128(int val) noexcept
    : Decimal128(static_cast<int64_t>(val))
{
}

Decimal128::Decimal128(int64_t val) noexcept
{
    constexpr uint64_t expon = uint64_t(DECIMAL_EXPONENT_BIAS_128) << DECIMAL_COEFF_HIGH_BITS;
    if (val < 0) {
        m_value.w[1] = expon | MASK_SIGN;
        m_value.w[0] = val == std::numeric_limits<int64_t>::lowest() ? val : ~val + 1;
    }
    else {
        m_value.w[1] = expon;
        m_value.w[0] = val;
    }
}

Decimal128::Decimal128(uint64_t val) noexcept
{
    BID_UINT64 tmp(val);
    BID_UINT128 expanded;
    bid128_from_uint64(&expanded, &tmp);
    memcpy(this, &expanded, sizeof(*this));
}

Decimal128::Decimal128(Bid32 val) noexcept
{
    if (val.u == DECIMAL_NULL_32) {
        m_value = DECIMAL_NULL_128;
        return;
    }
    unsigned flags = 0;
    BID_UINT32 x(val.u);
    BID_UINT128 tmp;
    bid32_to_bid128(&tmp, &x, &flags);
    memcpy(this, &tmp, sizeof(*this));
}

Decimal128::Decimal128(Bid64 val) noexcept
{
    if (val.w == DECIMAL_NULL_64) {
        m_value = DECIMAL_NULL_128;
        return;
    }
    unsigned flags = 0;
    BID_UINT64 x(val.w);
    BID_UINT128 tmp;
    bid64_to_bid128(&tmp, &x, &flags);
    memcpy(this, &tmp, sizeof(*this));
}

Decimal128::Decimal128(Bid128 coefficient, int exponent, bool sign) noexcept
{
    uint64_t sign_x = sign ? MASK_SIGN : 0;
    m_value = coefficient;
    uint64_t tmp = exponent + DECIMAL_EXPONENT_BIAS_128;
    m_value.w[1] |= (sign_x | (tmp << DECIMAL_COEFF_HIGH_BITS));
}

Decimal128::Decimal128(StringData init) noexcept
{
    unsigned flags = 0;
    BID_UINT128 tmp;
    bid128_from_string(&tmp, const_cast<char*>(init.data()), &flags);
    memcpy(this, &tmp, sizeof(*this));
}

Decimal128::Decimal128(null) noexcept
{
    m_value.w[0] = 0xaa;
    m_value.w[1] = 0x7c00000000000000;
}

Decimal128 Decimal128::nan(const char* init) noexcept
{
    Bid128 val;
    val.w[0] = strtol(init, nullptr, 10);
    val.w[1] = 0x7c00000000000000ull;
    return Decimal128(val);
}

bool Decimal128::is_null() const noexcept
{
    return m_value.w[0] == 0xaa && m_value.w[1] == 0x7c00000000000000;
}

bool Decimal128::is_nan() const noexcept
{
    return (m_value.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull;
}

bool Decimal128::to_int(int64_t& i) const noexcept
{
    BID_SINT64 res;
    unsigned flags = 0;
    BID_UINT128 x = to_BID_UINT128(*this);
    bid128_to_int64_int(&res, &x, &flags);
    if (flags == 0) {
        i = res;
        return true;
    }
    return false;
}


bool Decimal128::operator==(const Decimal128& rhs) const noexcept
{
    if (is_null() && rhs.is_null()) {
        return true;
    }
    unsigned flags = 0;
    int ret;
    BID_UINT128 l = to_BID_UINT128(*this);
    BID_UINT128 r = to_BID_UINT128(rhs);
    bid128_quiet_equal(&ret, &l, &r, &flags);
    if (ret) {
        return true;
    }
    bool lhs_is_nan = is_nan();
    bool rhs_is_nan = rhs.is_nan();
    if (lhs_is_nan && rhs_is_nan) {
        return m_value.w[1] == rhs.m_value.w[1] && m_value.w[0] == rhs.m_value.w[0];
    }
    return 0;
}

bool Decimal128::operator!=(const Decimal128& rhs) const noexcept
{
    return !(*this == rhs);
}

int Decimal128::compare(const Decimal128& rhs) const noexcept
{
    unsigned flags = 0;
    int ret;
    BID_UINT128 l = to_BID_UINT128(*this);
    BID_UINT128 r = to_BID_UINT128(rhs);
    bid128_quiet_less(&ret, &l, &r, &flags);
    if (ret)
        return -1;
    bid128_quiet_greater(&ret, &l, &r, &flags);
    if (ret)
        return 1;

    // Either equal or one or more is NaN
    bool lhs_is_nan = is_nan();
    bool rhs_is_nan = rhs.is_nan();
    if (!lhs_is_nan && !rhs_is_nan) {
        // Neither is NaN
        return 0;
    }
    if (lhs_is_nan && rhs_is_nan) {
        // We should have stable sorting of NaN
        if (m_value.w[1] == rhs.m_value.w[1]) {
            return m_value.w[0] == rhs.m_value.w[0] ? 0 : m_value.w[0] < rhs.m_value.w[0] ? -1 : 1;
        }
        else {
            return m_value.w[1] < rhs.m_value.w[1] ? -1 : 1;
        }
    }
    // nan vs non-nan should always order nan first
    return lhs_is_nan ? -1 : 1;
}

bool Decimal128::operator<(const Decimal128& rhs) const noexcept
{
    return compare(rhs) < 0;
}

bool Decimal128::operator>(const Decimal128& rhs) const noexcept
{
    return compare(rhs) > 0;
}

bool Decimal128::operator<=(const Decimal128& rhs) const noexcept
{
    return compare(rhs) <= 0;
}

bool Decimal128::operator>=(const Decimal128& rhs) const noexcept
{
    return compare(rhs) >= 0;
}

static Decimal128 do_multiply(BID_UINT128 x, BID_UINT128 mul) noexcept
{
    unsigned flags = 0;
    BID_UINT128 res;
    bid128_mul(&res, &x, &mul, &flags);
    return to_decimal128(res);
}

Decimal128 Decimal128::operator*(int64_t mul) const noexcept
{
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(Decimal128(mul));
    return do_multiply(x, y);
}

Decimal128 Decimal128::operator*(size_t mul) const noexcept
{
    Decimal128 tmp_mul(static_cast<uint64_t>(mul));
    return do_multiply(to_BID_UINT128(*this), to_BID_UINT128(tmp_mul));
}

Decimal128 Decimal128::operator*(int mul) const noexcept
{
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(Decimal128(mul));
    return do_multiply(x, y);
}

Decimal128 Decimal128::operator*(Decimal128 mul) const noexcept
{
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(mul);
    return do_multiply(x, y);
}

static Decimal128 do_divide(BID_UINT128 x, BID_UINT128 div)
{
    unsigned flags = 0;
    BID_UINT128 res;
    bid128_div(&res, &x, &div, &flags);
    return to_decimal128(res);
}

Decimal128 Decimal128::operator/(int64_t div) const noexcept
{
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(Decimal128(div));
    return do_divide(x, y);
}

Decimal128 Decimal128::operator/(size_t div) const noexcept
{
    Decimal128 tmp_div(static_cast<uint64_t>(div));
    return do_divide(to_BID_UINT128(*this), to_BID_UINT128(tmp_div));
}

Decimal128 Decimal128::operator/(int div) const noexcept
{
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(Decimal128(div));
    return do_divide(x, y);
}

Decimal128 Decimal128::operator/(Decimal128 div) const noexcept
{
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(div);
    return do_divide(x, y);
}

Decimal128& Decimal128::operator+=(Decimal128 rhs) noexcept
{
    unsigned flags = 0;
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(rhs);

    BID_UINT128 res;
    bid128_add(&res, &x, &y, &flags);
    memcpy(this, &res, sizeof(Decimal128));
    return *this;
}

Decimal128& Decimal128::operator-=(Decimal128 rhs) noexcept
{
    unsigned flags = 0;
    BID_UINT128 x = to_BID_UINT128(*this);
    BID_UINT128 y = to_BID_UINT128(rhs);

    BID_UINT128 res;
    bid128_sub(&res, &x, &y, &flags);
    memcpy(this, &res, sizeof(Decimal128));
    return *this;
}

bool Decimal128::is_valid_str(StringData str) noexcept
{
    unsigned flags = 0;
    BID_UINT128 tmp;
    bid128_from_string(&tmp, const_cast<char*>(str.data()), &flags);

    return (tmp.w[1] & 0x7c00000000000000ull) != 0x7c00000000000000ull;
}

std::string Decimal128::to_string() const noexcept
{
    if (is_null()) {
        return "NULL";
    }

    Bid128 coefficient;
    int exponen;
    bool sign;
    unpack(coefficient, exponen, sign);
    if (coefficient.w[1]) {
        char buffer[64];
        unsigned flags = 0;
        BID_UINT128 x;
        memcpy(&x, this, sizeof(Decimal128));
        bid128_to_string(buffer, &x, &flags);
        return std::string(buffer);
    }

    // The significant is stored in w[0] only. We can get a nicer printout by using this
    // algorithm here.
    std::string ret;
    if (sign)
        ret = "-";

    // check for NaN or Infinity
    if ((m_value.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) {
        if ((m_value.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) { // x is NAN
            ret += "NaN";
        }
        else {
            ret += "Inf";
        }
        return ret;
    }

    auto digits = util::to_string(coefficient.w[0]);
    size_t digits_before = digits.length();
    while (digits_before > 1 && exponen != 0) {
        digits_before--;
        exponen++;
    }
    ret += digits.substr(0, digits_before);
    if (digits_before < digits.length()) {
        // There are also digits after the decimal sign
        ret += '.';
        ret += digits.substr(digits_before);
    }
    if (exponen != 0) {
        ret += 'E';
        ret += util::to_string(exponen);
    }

    return ret;
}

auto Decimal128::to_bid32() const noexcept -> std::optional<Bid32>
{
    if (is_null()) {
        return DECIMAL_NULL_32;
    }
    unsigned flags = 0;
    BID_UINT32 buffer;
    BID_UINT128 tmp = to_BID_UINT128(*this);
    bid128_to_bid32(&buffer, &tmp, &flags);
    if (flags & ~BID_INEXACT_EXCEPTION)
        return {};
    return Bid32(buffer);
}

auto Decimal128::to_bid64() const noexcept -> std::optional<Bid64>
{
    if (is_null()) {
        return DECIMAL_NULL_64;
    }
    unsigned flags = 0;
    BID_UINT64 buffer;
    BID_UINT128 tmp = to_BID_UINT128(*this);
    bid128_to_bid64(&buffer, &tmp, &flags);
    if (flags & ~BID_INEXACT_EXCEPTION)
        return {};
    return Bid64(buffer);
}

void Decimal128::unpack(Bid128& coefficient, int& exponent, bool& sign) const noexcept
{
    sign = (m_value.w[1] & MASK_SIGN) != 0;
    int64_t exp = m_value.w[1] & MASK_EXP;
    exp >>= DECIMAL_COEFF_HIGH_BITS;
    exponent = int(exp) - DECIMAL_EXPONENT_BIAS_128;
    coefficient.w[0] = get_coefficient_low();
    coefficient.w[1] = get_coefficient_high();
}

bool operator==(Decimal128::Bid32 lhs, Decimal128::Bid32 rhs) noexcept
{
    static constexpr int DECIMAL_COEFF_BITS_32 = 23;
    static constexpr int DECIMAL_EXP_BITS_32 = 8;
    static constexpr unsigned MASK_COEFF_32 = (1 << DECIMAL_COEFF_BITS_32) - 1;
    static constexpr unsigned MASK_EXP_32 = ((1 << DECIMAL_EXP_BITS_32) - 1) << DECIMAL_COEFF_BITS_32;
    static constexpr unsigned MASK_SIGN_32 = 1 << (DECIMAL_COEFF_BITS_32 + DECIMAL_EXP_BITS_32);

    uint32_t x = lhs.u;
    uint32_t y = rhs.u;

    if (x == y) {
        return true;
    }

    unsigned sig_x = (x & MASK_COEFF_32);
    unsigned sig_y = (y & MASK_COEFF_32);
    bool x_is_zero = (sig_x == 0);
    bool y_is_zero = (sig_y == 0);

    if (x_is_zero && y_is_zero) {
        return true;
    }
    else if ((x_is_zero && !y_is_zero) || (!x_is_zero && y_is_zero)) {
        return false;
    }

    // Check if sign differs
    if ((x ^ y) & MASK_SIGN_32) {
        return false;
    }

    int exp_x = (x & MASK_EXP_32) >> DECIMAL_COEFF_BITS_32;
    int exp_y = (y & MASK_EXP_32) >> DECIMAL_COEFF_BITS_32;

    // Make exp_y biggest
    if (exp_x > exp_y) {
        std::swap(exp_x, exp_y);
        std::swap(sig_x, sig_y);
    }
    if (exp_y - exp_x > 6) {
        return false;
    }
    for (int lcv = 0; lcv < (exp_y - exp_x); lcv++) {
        sig_y = sig_y * 10;
        if (sig_y > 9999999) {
            return false;
        }
    }
    return (sig_y == sig_x);
}

} // namespace realm
